package net.lab1024.sa.admin.module.business.wms.stock.service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import com.alicp.jetcache.anno.Cached;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.module.business.dataStruct.queue.impl.LinkedListQueue;
import net.lab1024.sa.admin.module.business.wms.stock.dao.StockDao;
import net.lab1024.sa.admin.module.business.wms.stock.dao.StockWarnRuleDao;
import net.lab1024.sa.admin.module.business.wms.stock.domain.entity.StockWarnRuleEntity;
import net.lab1024.sa.admin.module.business.wms.stock.domain.form.StockWarnRuleAddForm;
import net.lab1024.sa.admin.module.business.wms.stock.domain.form.StockWarnRuleQueryForm;
import net.lab1024.sa.admin.module.business.wms.stock.domain.form.StockWarnRuleUpdateForm;
import net.lab1024.sa.admin.module.business.wms.stock.domain.vo.StockVO;
import net.lab1024.sa.admin.module.business.wms.stock.domain.vo.StockWarnRuleVO;
import net.lab1024.sa.admin.util.SpringContextUtil;
import net.lab1024.sa.base.common.util.SmartBeanUtil;
import net.lab1024.sa.base.common.util.SmartPageUtil;
import net.lab1024.sa.base.common.domain.ResponseDTO;
import net.lab1024.sa.base.common.domain.PageResult;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import jakarta.annotation.Resource;

/**
 * 库存预警规则表 Service
 *
 * @Author ADog
 * @Date 2025-09-20 16:13:18
 * @Copyright 1.0
 */

@Slf4j
@Service
public class StockWarnRuleServiceImpl {

    @Resource
    private StockWarnRuleDao stockWarnRuleDao;


    @Resource
    private StockDao stockDao;

    @Resource
    private RabbitTemplate rabbitTemplate;

    // MQ常量定义（放在StockWarnRuleService类中）
    private static final String STOCK_WARN_EXCHANGE = "stock_warn_exchange"; // 交换机名称
    private static final String STOCK_WARN_ROUTING_KEY = "stock.warn.key";    // 路由键
    private static final String STOCK_WARN_QUEUE = "stock_warn_queue";        // 队列名称

    /**
     * 分页查询
     */
    public PageResult<StockWarnRuleVO> queryPage(StockWarnRuleQueryForm queryForm) {
        Page<?> page = SmartPageUtil.convert2PageQuery(queryForm);
        List<StockWarnRuleVO> list = stockWarnRuleDao.queryPage(page, queryForm);
        return SmartPageUtil.convert2PageResult(page, list);
    }

    /**
     * 添加
     */
    public ResponseDTO<String> add(StockWarnRuleAddForm addForm) {
        StockWarnRuleEntity stockWarnRuleEntity = SmartBeanUtil.copy(addForm, StockWarnRuleEntity.class);
        stockWarnRuleDao.insert(stockWarnRuleEntity);
        return ResponseDTO.ok();
    }

    /**
     * 更新
     */
    public ResponseDTO<String> update(StockWarnRuleUpdateForm updateForm) {
        StockWarnRuleEntity stockWarnRuleEntity = SmartBeanUtil.copy(updateForm, StockWarnRuleEntity.class);
        stockWarnRuleDao.updateById(stockWarnRuleEntity);
        return ResponseDTO.ok();
    }

    /**
     * 批量删除
     */
    public ResponseDTO<String> batchDelete(List<Long> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return ResponseDTO.ok();
        }

        stockWarnRuleDao.deleteBatchIds(idList);
        return ResponseDTO.ok();
    }

    /**
     * 单个删除
     */
    public ResponseDTO<String> delete(Long ruleId) {
        if (null == ruleId) {
            return ResponseDTO.ok();
        }

        stockWarnRuleDao.deleteById(ruleId);
        return ResponseDTO.ok();
    }

    /**
     * 核心预警检查入口
     * 建议每30分钟或1小时执行一次
     */
//    @Scheduled(cron = "0 0/30 * * * ?") // 每30分钟一次
    @Scheduled(fixedRate = 10000) // 每30分钟一次
    public void checkAllWarnings() {
        log.info("开始执行全量库存预警检查...");
        //1 、检查物料高库存和低库存(基于当前的库存量)
        checkInventoryLevelWarnings();

        //2、检查临期和过期库存（基于过期时间）
//         checkExpirationWarnings();
        log.info("库存预警检查执行完毕。");
    }

    /**
     * 检查库存水平预警（低库存、高库存）
     * 策略：按物料分组汇总库存，再应用规则
     */

    private void checkInventoryLevelWarnings() {
        // 1、先获取所有启用的库存水平类规则（预加载到内存，避免N+1查询）的数据
        // 改用 SpringContextUtil 获取自身代理对象，触发缓存
        StockWarnRuleServiceImpl self = SpringContextUtil.getBean(StockWarnRuleServiceImpl.class);
        List<StockWarnRuleVO> enabledRules = self.findByWarnTypeInAndIsEnabled(Arrays.asList(1, 4), true);

        // 2、按物料ID分组规则
        Map<Long, List<StockWarnRuleVO>> rulesByMaterial = enabledRules.stream()
                .collect(Collectors.groupingBy(StockWarnRuleVO::getMaterialId));

        // 3、获取所有需要检查的物料ID
        Set<Long> materialIdsToCheck = rulesByMaterial.keySet();
        if (materialIdsToCheck.isEmpty()) {
            return;
        }
        // 4、准备一个队列存储预警信息
        LinkedListQueue<String> linkedListQueue = new LinkedListQueue<>();
        // 5、批量查询这些物料的库存汇总信息
        for (Long materialId : materialIdsToCheck) {
            // 5、1 根据ID查询所有物料
            List<StockVO> stocks = stockDao.findByMaterialIdAndIsDeleted(materialId, false);
            if (stocks.isEmpty()) continue;
            // 5、2 计算该物料的总可用库存
            BigDecimal totalAvailable = stocks.stream()
                    .map(stock -> stock.getStockQuantity().subtract(stock.getLockedQuantity()))
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            // 5、3 应用该物料的所有规则
            for (StockWarnRuleVO rule : rulesByMaterial.get(materialId)) {
                BigDecimal threshold = new BigDecimal(rule.getWarnThreshold());
                boolean shouldWarn = false;
                String warnDesc = "";

                if (rule.getWarnType() == 1) { // 低库存
                    shouldWarn = totalAvailable.compareTo(threshold) < 0;
                    warnDesc = String.format("物料[%s]库存不足。当前可用：%s，阈值：%s",
                            materialId, totalAvailable, threshold);
                } else if (rule.getWarnType() == 4) { // 高库存
                    shouldWarn = totalAvailable.compareTo(threshold) > 0;
                    warnDesc = String.format("物料[%s]库存过高。当前可用：%s，阈值：%s",
                            materialId, totalAvailable, threshold);
                }
                if (shouldWarn) {
                    // 先判断队列是否已存在该信息（避免重复广播）
                    if (!linkedListQueue.isDuplicate(warnDesc)) {
                        linkedListQueue.enqueue(warnDesc); // 入队
                        // 广播预警信息(改成mq)
//                        MessageEndpoint.broadcastAllUsers(linkedListQueue.toString());
                    }
                }
            }
        }
        // 3. 核心改造：若队列有预警消息，发送到MQ（而非直接广播）
        if (!linkedListQueue.isEmpty()) {
            String warnMessages = linkedListQueue.toString(); // 获取所有预警消息（已在LinkedListQueue中实现toString）
            try {
                // 发送消息到RabbitMQ：交换机 + 路由键 + 消息内容
                rabbitTemplate.convertAndSend(STOCK_WARN_EXCHANGE, STOCK_WARN_ROUTING_KEY, warnMessages);
                log.info("MQ消息发送成功，内容：{}", warnMessages);
            } catch (Exception e) {
                log.error("MQ消息发送失败，内容：{}", warnMessages, e);
                // 可选：发送失败时降级处理（如直接广播，避免消息丢失）
//                MessageEndpoint.broadcastAllUsers(warnMessages);
            }
        }

        // 4. 打印队列内容（原有逻辑不变）
        System.out.println("linkedListQueue = " + linkedListQueue.toString());
    }


    @Cached(
            area = "ruleCache",
            name = "stockWarnRule:enabled:",
            key = "#warnTypes.toString() + '_' + #isEnabled", // 明确类型后，toString() 才能正确生成 key
            expire = 1800
    )
    public List<StockWarnRuleVO> findByWarnTypeInAndIsEnabled(List<Integer> warnTypes, Boolean isEnabled) {
        return stockWarnRuleDao.findByWarnTypeInAndIsEnabled(warnTypes, isEnabled);
    }
}

